// main
package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"os/signal"

	"github.com/bitly/go-simplejson"

	mqtt "github.com/eclipse/paho.mqtt.golang"
)

var messagePubHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
	fmt.Printf("Received message: %s from topic: %s\n", msg.Payload(), msg.Topic())

	//读取发布配置，备份war包，替换war包，重启tomcat或者docker
	issuejson := string(msg.Payload())
	fmt.Println(issuejson)

	//读本地配置 war包路径 存储命令等
	pwd, _ := os.Getwd()
	localjson := readFile(pwd + "/" + "jenkinsmqtt.json")
	fmt.Println(localjson)

	//发布模块解析
	module, link := readIssueModule(issuejson)
	fmt.Println(module)
	fmt.Println(link)

	//模块发布
	issueModuleLocalJson(module, link, localjson)

	//

}

var connectHandler mqtt.OnConnectHandler = func(client mqtt.Client) {
	fmt.Println("Connected")
}

var connectLostHandler mqtt.ConnectionLostHandler = func(client mqtt.Client, err error) {
	fmt.Printf("Connect lost: %v", err)
}

func main() {

	//合建chan
	c := make(chan os.Signal)
	//监听指定信号 ctrl+c kill
	signal.Notify(c, os.Interrupt, os.Kill)
	//阻塞直到有信号传入
	fmt.Println("启动")

	//执行具体方法
	initmqtt()

	//阻塞直至有信号传入
	s := <-c
	fmt.Println("退出信号", s)

}

func initmqtt() {
	var broker = "mq.tongxinmao.com"
	var port = 1883
	opts := mqtt.NewClientOptions()
	opts.AddBroker(fmt.Sprintf("tcp://%s:%d", broker, port))
	opts.SetDefaultPublishHandler(messagePubHandler)
	opts.OnConnect = connectHandler
	opts.OnConnectionLost = connectLostHandler
	client := mqtt.NewClient(opts)
	if token := client.Connect(); token.Wait() && token.Error() != nil {
		panic(token.Error())
	}

	sub(client)
}

func sub(client mqtt.Client) {
	topic := "topic/sunwardtest"
	token := client.Subscribe(topic, 1, nil)
	token.Wait()
	fmt.Printf("Subscribed to topic: %s\n", topic)
}

// readFile 使用ioutil.ReadFile 直接从文件读取到 []byte中
func readFile(fileName string) string {
	f, err := ioutil.ReadFile(fileName)
	if err != nil {
		log.Printf("读取文件失败:%#v", err)

		return ""
	}
	return string(f)
}

//读取消息的发布模块名和链接
func readIssueModule(issuejson string) (string, string) {
	buf := bytes.NewBuffer([]byte(issuejson))
	js, _ := simplejson.NewFromReader(buf)

	fmt.Println(js)

	var each_map = make(map[string]interface{})
	each_map, _ = js.Map()

	module := each_map["module"].(string)
	link := each_map["link"].(string)

	return module, link
}

//根据模块名和模块匹配本地json模块发布
func issueModuleLocalJson(imodule string, link string, localjson string) {
	//读本地配置 war包路径 存储命令等
	fmt.Println(localjson)

	buf := bytes.NewBuffer([]byte(localjson))
	js, _ := simplejson.NewFromReader(buf)

	fmt.Println(js)
	//获取json字符串中的  数组
	rows, _ := js.Array()
	fmt.Println(rows)

	//遍历rows数组
	for _, row := range rows {
		each_map := row.(map[string]interface{})
		module := each_map["module"].(string)
		warpath := each_map["warpath"].(string)
		warname := each_map["warname"].(string)
		backpath := each_map["backpath"].(string)
		stop := each_map["stop"].(string)
		start := each_map["start"].(string)
		transfer := each_map["transfer"].(string)
		// restart := each_map["restart"].(string)

		if module == imodule {
			fmt.Println("找到对应模块")
			exec_shell("cd " + backpath)
			pwd, _ := os.Getwd()
			fmt.Println("当前目录" + pwd)
			exec_shell(transfer + " " + link)
			exec_shell(stop)
			exec_shell("cp -f" + " " + warname + " " + warpath)
			exec_shell(start)
		} else {
			break
		}
	}

}

//阻塞式的执行外部shell命令的函数,等待执行完毕并返回标准输出
func exec_shell(s string) (string, error) {
	//函数返回一个*Cmd，用于使用给出的参数执行name指定的程序
	cmd := exec.Command("/bin/bash", "-c", s)

	//读取io.Writer类型的cmd.Stdout，再通过bytes.Buffer(缓冲byte类型的缓冲器)将byte类型转化为string类型(out.String():这是bytes类型提供的接口)
	var out bytes.Buffer
	cmd.Stdout = &out

	//Run执行c包含的命令，并阻塞直到完成。  这里stdout被取出，cmd.Wait()无法正确获取stdin,stdout,stderr，则阻塞在那了
	err := cmd.Run()
	checkErr(err)

	return out.String(), err
}

//错误处理函数
func checkErr(err error) {
	if err != nil {
		fmt.Println(err)
		panic(err)
	}
}
